package com.nage.components.collision;

import android.util.Log;

import com.nage.components.Component;
import com.nage.components.display.Shape;
import com.nage.components.movement.Physics;
import com.nage.components.movement.Vector2D;
import com.nage.engine.GameGraphException;
import com.nage.engine.GameObject;

/**
 * Component for making a game object Collidable. ie. Part of the collision detection
 * system. This will register the object with the CollisionManager which is responsible
 * for detecting collisions between objects and calling the onCollide() method when
 * this occurs.
 * 
 * @author lukeo05
 *
 */
public class Collidable extends Component {
	

	
	
	private static final float e = 0.7f;
	/**  
	 * The shape that is used to test collisions against
	 */
	CollisionMask mask;
	Shape shape; // used to edit colours depending on collision status
	protected Physics m_Physics;

	protected int collisions;
	
	public Collidable(GameObject p) {
		super(p);
		type = COLLIDABLE;
		collisions = 0;
		CollisionManager.register(this); // is it okay to pass a reference to this here. hasn't been fully instantiated?
	}

	@Override
	public boolean findLinks() throws GameGraphException {
		mask = (CollisionMask) parent.getComponent(Component.COLLISION_MASK);
		shape = (Shape) parent.getComponent(SHAPE);
		m_Physics = (Physics) parent.getComponent(PHYSICS);
		if(mask==null || shape==null || m_Physics==null) {
			String msg = "Error linking Components withing Collidable. CollisionMask ";
			msg += (mask==null ? "not found" : "found");
			msg += ", Shape ";
			msg += (shape==null ? "not found" : "found");
			msg += ", Physics ";
			msg += (m_Physics==null ? "not found" : "found");
			throw new GameGraphException(msg);
		}
		return true;
	}
	
	@Override
	public void update(long delta) {
		return;
	}
	
	
	@Override
	public String toString() {
		return "Object: "+parent.m_Name+", type: "+type;
	}


	
	/** 
	 * Called when this object initially collides with another object.
	 */
	public void onCollision(Collision c) {
		collisions++;
		shape.setRGB("ff3333");
		Log.d("Collidable", "onCollision() called for Collision c: "+c.toString());
		
		// Calculate the impulse value using big equation, and then apply
		// as impulse vector to each object (one positive and one negative)
		// which is calculated as j/m * n
		// j = impulse value
		// m = mass of object
		// n = normal vector of collision
		
		// n is calculated as the normal vector to the edge of collision. so
		// find the edge that the collision occured on, make a vector on that edge
		// and then find the normal to that vector (cross product = 0 (?))
		
		// j is calculated complexly: need coefficient of restitution (bouncyness)
		// and vAB, which is the difference in velocities between the two objects?
		// vAB = vAP - vBP, or it is the difference between the velocities! yes!
		
		// http://chrishecker.com/images/e/e7/Gdmphys3.pdf
		
		//Vector2D n = c.getCollisionNormal(); // n = collision normal
		Vector2D n, collisionPoint;
		collisionPoint = c.getCollisionPoint();
		if(collisionPoint==null) {
			return;
		}
		n = c.getCollisionNormal(collisionPoint);
		
		
		
		if(n==null) {
			return;
		}
		Vector2D vAB = c.getVelocityDifference(); // vAB = the difference between the velocities
												// of the two different objects.
		
		Log.d("Collidable", "n = "+n.toString()+", vAB = "+vAB.toString());
		
		float j = getCollisionImpulse(vAB, n, c.collidable1.m_Physics.mass, c.collidable2.m_Physics.mass);
		if(j==Float.NaN) {
			return;
		}
		j *= 10;
		Log.d("Collidable", "j = "+j);

		c.collidable1.m_Physics.addImpulse(n.multiply(j/c.collidable1.m_Physics.mass));
		c.collidable2.m_Physics.addImpulse((n.multiply(j/c.collidable2.m_Physics.mass)).multiply(-1));
	

		
	}
	
	private float getCollisionImpulse(Vector2D vAB, Vector2D n, float massA,
			float massB) {
		
		vAB = vAB.multiply(1+e);
		float numerator = Vector2D.dot(vAB.multiply(-1), n);
		float denominator = Vector2D.dot(n, n.multiply(1/massA + 1/massB));
		
		return numerator/denominator;
	}

	/**
	 * Called when this object seperates from an object it has previously collided with.
	 */
	public void onSeperation() {
		collisions--;
		if(collisions==0) {
		}
		shape.setRGB("3333ff");
	}

}
